/*
 * Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.scancodelib;

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;


import com.honeywell.barcode.HSMDecodeComponent;
import com.honeywell.barcode.HSMDecodeResult;
import com.honeywell.barcode.HSMDecoder;
import com.honeywell.barcode.Symbology;
import com.honeywell.barcode.WindowMode;
import com.honeywell.license.ActivationManager;
import com.honeywell.license.ActivationResult;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;


/**
 * <pre>
 *     desc   : 自定义实现的扫描Fragment
 *     author : xuexiang
 *     time   : 2018/5/4 上午12:03
 * </pre>
 */
public class ScanCaptureFragment extends Fragment implements ScanCustomPluginResultListener {


    private MediaPlayer mMediaPlayer;
    private boolean mPlayBeep;
    private static final float BEEP_VOLUME = 0.10f;
    private boolean mVibrate;
    private HSMDecodeComponent mDecodeComponent;
    private HSMDecoder mHSMDecoder;
    private ScanCustomPlugin mCustomPlugin;

    /**
     * 构建扫描Fragment
     *
     * @param layoutId 布局id
     * @return
     */
    public static ScanCaptureFragment newInstance(int layoutId) {
        if (layoutId == -1) {
            return null;
        }
        ScanCaptureFragment lScanCaptureFragment = new ScanCaptureFragment();
        Bundle bundle = new Bundle();
        bundle.putInt(ScanCode.KEY_LAYOUT_ID, layoutId);
        lScanCaptureFragment.setArguments(bundle);
        return lScanCaptureFragment;
    }

    /**
     * 处理Activity【防止锁屏和fragment里面放surfaceView，第一次黑屏的问题】
     *
     * @param activity
     */
    public static void onCreate(Activity activity) {
        if (activity != null) {
            // 防止锁屏
            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
            //为了解决fragment里面放surfaceview，第一次黑屏的问题
            activity.getWindow().setFormat(PixelFormat.TRANSLUCENT);
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        onCreate(getActivity());
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        Bundle bundle = getArguments();
        View view = null;
        if (bundle != null) {
            int layoutId = bundle.getInt(ScanCode.KEY_LAYOUT_ID);
            if (layoutId != -1) {
                //自定义布局
                view = inflater.inflate(layoutId, null);
            }
        }

        if (view == null) {
            view = inflater.inflate(R.layout.scan_fragment_default_capture_layout, null);
        }
        //初始化失败时应该加一个处理
        if (!ActivationManager.isActivated(getActivity())) {
            ActivationResult activationResult = ActivationManager.activate(getActivity(), "trial-zhilu-tjian-05312019");
            //Toast.makeText(getActivity(), "Activation Result: " + activationResult, Toast.LENGTH_LONG).show();
        }

        final DisplayMetrics lDisplayMetrics = getActivity().getResources().getDisplayMetrics();
        final int lWidthPixels = lDisplayMetrics.widthPixels;
        final int lHeightPixels = lDisplayMetrics.heightPixels;
        final AutoScannerView lAutoScannerView = view.findViewById(R.id.viewfinder_view);
        lAutoScannerView.post(new Runnable() {
            @Override
            public void run() {
                Rect lCanvasFrameRect = lAutoScannerView.getCanvasFrameRect();
                if (lCanvasFrameRect != null) {
                    mHSMDecoder.setWindowMode(WindowMode.WINDOWING);
                    int imgWidth = lCanvasFrameRect.right - lCanvasFrameRect.left;
                    int left = count(lCanvasFrameRect.left, lWidthPixels);
                    int right =count(lWidthPixels - lCanvasFrameRect.left,lWidthPixels);
                    int top =count(lCanvasFrameRect.top,lHeightPixels);
                    //44为标题栏的高度
                    int bottom=top+count((int) (44 * lDisplayMetrics.scaledDensity + imgWidth),lHeightPixels);
                    ScanLogUtils.d("scan code  left:" + left + " right:" + right + " top:" + top + " bottom:" + bottom);
                    mHSMDecoder.setWindow(top, bottom, left, right);

                }
            }
        });

        mDecodeComponent = (HSMDecodeComponent) view.findViewById(R.id.hsm_decodeComponent);
        mHSMDecoder = HSMDecoder.getInstance(this.getActivity());
        mHSMDecoder.enableSymbology(Symbology.UPCA);
        mHSMDecoder.enableSymbology(Symbology.CODE128);
        mHSMDecoder.enableSymbology(Symbology.CODE39);
        mHSMDecoder.enableSymbology(Symbology.QR);
        mHSMDecoder.enableSymbology(Symbology.EAN8);
        mHSMDecoder.enableSymbology(Symbology.EAN13);
        mHSMDecoder.enableFlashOnDecode(false);
        mHSMDecoder.enableSound(true);
        mHSMDecoder.enableAimer(true);



        return view;
    }


    private int count(int diliverNum, int queryMailNum) {
        return (int) (diliverNum*1.0/queryMailNum*100);
    }


    @Override
    public void onResume() {
        super.onResume();

        mPlayBeep = true;
        AudioManager audioService = (AudioManager) requireNonNull(getActivity()).getSystemService(Context.AUDIO_SERVICE);
        if (audioService != null && audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) {
            mPlayBeep = false;
        }
        initBeepSound();
        mVibrate = true;

    }

    @Override
    public void onPause() {
        super.onPause();

    }

    @Override
    public void onStart() {
        super.onStart();
        mCustomPlugin = new ScanCustomPlugin(getActivity().getApplicationContext());
        mCustomPlugin.addResultListener(this);
        mHSMDecoder.initCameraConnection();
        mHSMDecoder.registerPlugin(mCustomPlugin);
    }

    @Override
    public void onStop() {
        super.onStop();
        mCustomPlugin.removeResultListener(this);
        mHSMDecoder.releaseCameraConnection();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();

    }

    /**
     * 开关闪光灯
     *
     * @param isEnable 是否开启闪光灯
     */
    public void enableFlashLight(boolean isEnable) throws RuntimeException {
        if (isEnable) {
            Camera camera = mHSMDecoder.getCamera();
            if (camera != null) {
                Camera.Parameters parameter = camera.getParameters();
                parameter.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
                camera.setParameters(parameter);
            }
        } else {
            Camera camera = mHSMDecoder.getCamera();
            if (camera != null) {
                Camera.Parameters parameter = camera.getParameters();
                parameter.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
                camera.setParameters(parameter);
            }
        }
    }

    private void initBeepSound() {
        if (mPlayBeep && mMediaPlayer == null) {
            // The volume on STREAM_SYSTEM is not adjustable, and users found it
            // too loud,
            // so we now play on the music stream.
            requireNonNull(getActivity()).setVolumeControlStream(AudioManager.STREAM_MUSIC);
            mMediaPlayer = new MediaPlayer();
            mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
            mMediaPlayer.setOnCompletionListener(beepListener);

            AssetFileDescriptor file = getResources().openRawResourceFd(R.raw.beep);
            try {
                mMediaPlayer.setDataSource(file.getFileDescriptor(),
                        file.getStartOffset(), file.getLength());
                file.close();
                mMediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME);
                mMediaPlayer.prepare();
            } catch (IOException e) {
                mMediaPlayer = null;
            }
        }
    }

    private static final long VIBRATE_DURATION = 200L;

    public void playBeepSoundAndVibrate() {
        if (mPlayBeep && mMediaPlayer != null) {
            mMediaPlayer.start();
        }
        if (mVibrate) {
            Vibrator vibrator = (Vibrator) requireNonNull(getActivity()).getSystemService(Context.VIBRATOR_SERVICE);
            if (vibrator != null) {
                vibrator.vibrate(VIBRATE_DURATION);
            }
        }
    }

    /**
     * When the beep has finished playing, rewind to queue up another one.
     */
    private final MediaPlayer.OnCompletionListener beepListener = new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            mediaPlayer.seekTo(0);
        }
    };

    private ScanAnalyzeCallback mScanAnalyzeCallback;

    public ScanAnalyzeCallback getScanAnalyzeCallback() {
        return mScanAnalyzeCallback;
    }

    public void setScanAnalyzeCallback(ScanAnalyzeCallback pScanAnalyzeCallback) {
        this.mScanAnalyzeCallback = pScanAnalyzeCallback;
    }


    public Handler getHandler() {
        return mHandler;
    }

    private boolean mIsControResult = true;
    private long mPreSendTime = 0;
    private Handler mHandler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 12:
                    mIsControResult = true;
                    break;
                case 13:
                    String result = (String) msg.obj;
                    String encoding = ScanStringUtils.getEncoding(result);
                    if (encoding.equals("")) {
                        ScanToastUtils.showShort("解码异常 请重试");
                        return;
                    }
                    try {
                        result = new String(result.getBytes(encoding), "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    if (!mScanResultList.contains(result)) {
                        mScanResultList.add(result);
                        playBeepSoundAndVibrate();
                        mIsControResult = false;
                        mScanAnalyzeCallback.onAnalyzeSuccess(null, result);
                    } else {
                        long currentTime = System.currentTimeMillis();
                        long flagTime = currentTime - mPreSendTime;
                        if (flagTime > 3000) {
                            mPreSendTime = currentTime;
                            playBeepSoundAndVibrate();
                            mIsControResult = false;
                            mScanAnalyzeCallback.onAnalyzeSuccess(null, result);
                        }
                    }

                    break;
            }
        }
    };


    private List<String> mScanResultList = new ArrayList<>();

    @Override
    public void onCustomPluginResult(HSMDecodeResult[] barcodeData) {
        if (mIsControResult) {
            HSMDecodeResult firstResult = barcodeData[0];
            String msg = "Scan Count: " + "\n\n" +
                    "onHSMDecodeResult\n" +
                    "Data: " + firstResult.getBarcodeData() + "\n" +
                    "Symbology: " + firstResult.getSymbology() + "\n" +
                    "Length: " + firstResult.getBarcodeDataLength() + "\n" +
                    "Decode Time: " + firstResult.getDecodeTime() + "ms";

            ScanLogUtils.d(" scan result = " + msg);
            //mScanAnalyzeCallback.onAnalyzeSuccess(null, firstResult.getBarcodeData());
            Message lMessage = Message.obtain();
            lMessage.what = 13;
            lMessage.obj = firstResult.getBarcodeData();
            mHandler.sendMessage(lMessage);
        }
    }


    public static <T> T requireNonNull(T obj) {
        if (obj == null) {
            throw new NullPointerException();
        }
        return obj;
    }


}
